using System;
using System.Collections.Generic;
using System.Text;
using agsXMPP;
using System.Threading;
using System.Security;

namespace PoshXmpp
{
    public class XmppClientFactory
    {
        ManualResetEvent _loginSuccess = new ManualResetEvent(false);
        ManualResetEvent _loginFailure = new ManualResetEvent(false);
        ManualResetEvent _connectError = new ManualResetEvent(false);


        WaitHandle[] _loginComplete;

        public XmppClientFactory()
        {
            _loginComplete = new WaitHandle[] { 
                _loginSuccess,
                _loginFailure,
                _connectError
            };
        }

        string _loginErrorMessage = "Error logging in";

        static public XmppClient CreateXmppClient(string jabberId, SecureString password)
        {
            return CreateXmppClient(new Jid(jabberId), password, null, false);
        }
        static public XmppClient CreateXmppClient(Jid user, SecureString password)
        {
            return CreateXmppClient(user, password, null, false);
        }
        static public XmppClient CreateXmppClient(string jabberId, SecureString password, bool reconnect)
        {
            return CreateXmppClient( new Jid(jabberId), password, null, reconnect);
        }
        static public XmppClient CreateXmppClient(Jid user, SecureString password, bool reconnect)
        {
            return CreateXmppClient(user, password, null, reconnect);
        }
        static public XmppClient CreateXmppClient(string jabberId, SecureString password, string httpPollingServer)
        {
            return CreateXmppClient(new Jid(jabberId), password, httpPollingServer, false);
        }
        static public XmppClient CreateXmppClient(Jid user, SecureString password, string httpPollingServer)
        {
            return CreateXmppClient(user, password, httpPollingServer, false);
        }
        static public XmppClient CreateXmppClient(string jabberId, SecureString password, string httpPollingServer, bool reconnect)
        {
            return CreateXmppClient(new Jid(jabberId), password, httpPollingServer, reconnect);
        }
        static public XmppClient CreateXmppClient(Jid user, SecureString password, string httpPollingServer, bool reconnect)
        {
            XmppClient xmpp = new XmppClient(user, password, reconnect);

            if (String.IsNullOrEmpty(httpPollingServer))
            {
                xmpp.AutoResolveConnectServer = true;
            }
            else
            {
                xmpp.SocketConnectionType = agsXMPP.net.SocketConnectionType.HttpPolling;
                xmpp.ConnectServer = httpPollingServer; // "http://im.flosoft.biz:5280/http-poll/"
            }
            //xmpp.Port = 5280;

            XmppClientFactory handler = new XmppClientFactory();
            return handler.Connect(xmpp);
        }

        public XmppClient Connect(XmppClient xmpp)
        {

            xmpp.OnLogin += new ObjectHandler(OnLoginComplete);
            xmpp.OnError += new ErrorHandler(OnError);
            xmpp.OnAuthError += new XmppElementHandler(OnLoginError);

            //ThreadPool.QueueUserWorkItem(new WaitCallback(LoginThread), xmpp);
            //xmpp.Open(xmpp.Username,xmpp.Password);
            xmpp.Open();

            // wait up to five seconds for the login to happen
            WaitHandle.WaitAny(_loginComplete, 5000, true);

            if (xmpp.Authenticated)
            {
                return xmpp;
            }
            else
            {
                xmpp.Close();
                throw new OperationCanceledException(_loginErrorMessage);
            }
        }

        public void LoginThread(object xmpp)
        {
            ((XmppClientConnection)xmpp).Open();
        }

        void OnLoginComplete(object sender)
        {
            _loginSuccess.Set();
        }

        void OnLoginError(object sender, agsXMPP.Xml.Dom.Element e)
        {
            _loginErrorMessage = e.InnerXml.ToString();
            _loginFailure.Set();
        }

        void OnError(object sender, Exception ex)
        {
            _loginErrorMessage = ex.Message + "\n\n" + ex.StackTrace;
            _connectError.Set();
        }
    }
}
